#include "TcpServerApp.h"

const string SERVER_IP = "120.24.100.92";
const string USER_NAME = "itoffice";
const string PASSWORD  = "itoffice";
const string DATA_BASE = "IotSystemDataBase";

const int RECV_BUF_SIZE = 100;       //单次接收的数据长度
const int MAX_DATA_SIZE = 10 * 1024; //数据的最大长度

DeviceManager g_DeviceManage;
/*********** request *********/
enum
{
 LOGIN,
 CONNECT_DEVICE,
 CURTAIN_STATE,
 CURTAIN_MOVE
};
const string Request[20] =
{
"login",
"connect_device",
"curtain_state",
"curtain_move"
};
/*********** order *********/
enum
{
  YES,
  NO,
  ASK,
  DEVICE,
  USER,
  ID,
  ACK
};
const string SendOrder[20] =
{
"yes",
"no",
"ask",
"10002",
"10001",
"id",
"ack"
};


/********************************
函  数：ConnectRUN
功  能：处理链接请求的主函数
参  数：v_socket与服务器连接的socket

返回值：
说  明：
********************************/
void ConnectRUN(StreamSocket v_socket)             //连接
{

	LOG(INFO) << "New Connect";
	printf("New Connect!\r\n");
    v_socket.setKeepAlive(true);
    switch(nAskRole(v_socket))
    {
        case DEVICE : CommunicateWithDevice(v_socket);break;
        case USER   : CommunicateWithUser(v_socket);break;
        default:      v_socket.shutdown();break;
    }

    return;
}
  /********************************
 函  数：
 功  能：
 参  数：

 返回值：
 说  明：
 ********************************/
void CommunicateWithDevice(StreamSocket v_socket)
{

 CServerAppForDevice  *AppForDevice = new CServerAppForDevice(v_socket);
	try
	{
		AppForDevice->m_setConnectState(true); //更新状态

		AppForDevice->m_bFormatSend(SendOrder[ID]);
        usleep(200 * 1000);
		string str;
		AppForDevice->m_bFormatRecv(str);
        printf("Device Id : %s\r\n",str.c_str());
        AppForDevice->m_nDeviceId = atoi(str.c_str());

        g_DeviceManage.AddDeviceNodeToList(AppForDevice);

		while(1)
		{
                usleep(200 * 1000);
                if(!AppForDevice->m_bkeepAlive())
                {
                  AppForDevice->m_socket.shutdown();
                  break;
                }
                if(AppForDevice->m_bGetSendFlag())
                {
                  AppForDevice->m_bMovieCurtain();
                  AppForDevice->m_bSetSendFlag(false);
                }

		}
		g_DeviceManage.DeletDeviceNodeByDeviceId(AppForDevice->m_nDeviceId);

		delete(AppForDevice);
	}
	catch( std::exception& e )
	{
		v_socket.shutdown();
		AppForDevice->m_setConnectState(false);

		g_DeviceManage.DeletDeviceNodeByDeviceId(AppForDevice->m_nDeviceId);
		delete(AppForDevice);
		LOG(ERROR) << e.what();
	}
}
  /********************************
 函  数：
 功  能：
 参  数：

 返回值：
 说  明：
 ********************************/
void CommunicateWithUser(StreamSocket v_socket)
{
    CServerAppForUser  AppForUser;
	try
	{
		v_socket.setKeepAlive(true);
		AppForUser.m_setConnectState(true); //更新状态
		AppForUser.m_socket = v_socket;
		AppForUser.m_bFormatSend(SendOrder[ID]);

		AppForUser.m_ProcessRequest();      //处理请求线程

		while(1)
		{
        /**************************   数据  ***************************/
			 string strRecv;
			 if(!AppForUser.m_bFormatRecv(strRecv))
			 {
				 v_socket.shutdown();
				 AppForUser.m_setConnectState(false);
				 break;
			 }
		/************************   处理数据  ***************************/
            AppForUser.m_bPushRequestToList(strRecv);
		}

		pthread_mutex_lock(&AppForUser.m_MutexForDestory); //等待其他线程结束
		pthread_mutex_unlock(&AppForUser.m_MutexForDestory);
		AppForUser.m_bWriteLogoutTime();
	}
	catch( std::exception& e )
	{
		v_socket.shutdown();
		AppForUser.m_setConnectState(false);
		pthread_mutex_lock(&AppForUser.m_MutexForDestory);//等待其他线程结束
		pthread_mutex_unlock(&AppForUser.m_MutexForDestory);
		AppForUser.m_bWriteLogoutTime();
		LOG(ERROR) << e.what();
	}
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
short nAskRole(StreamSocket v_socket)
{
    if(!bFormatSend(v_socket,SendOrder[ASK]))
    {
      LOG(ERROR) << "Send Error";
      v_socket.shutdown();
      return 0;
    }
    usleep(300 * 1000);
    string strRecv;
    if(!bFormatRecv(v_socket,strRecv))
     {
      LOG(ERROR) << "Recv Error";
      v_socket.shutdown();
      return 0;
    }

    if(strRecv == SendOrder[DEVICE])
    {
     LOG(INFO) << "Connect is Device";
     printf("Connect is Device\r\n");
     return DEVICE;
    }
    if(strRecv == SendOrder[USER])
    {
     LOG(INFO) << "Connect is User";
     printf("Connect is User\r\n");
     return USER;
    }

    LOG(ERROR) << "Unkonwn Connect";
    return 0;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
CServerApp::CServerApp()
{
	m_bConnected = false;
	pthread_mutex_init(&m_MutexForDestory,NULL);
	pthread_mutex_init(&m_MutexForState,NULL);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
CServerApp::~CServerApp()
{
	pthread_mutex_destroy(&m_MutexForDestory);
	pthread_mutex_destroy(&m_MutexForState);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
 CServerAppForUser::CServerAppForUser()
{
    m_nLoginInfoId = 0;
    m_nUserId = 0;
	pthread_mutex_init(&m_MutexForRecvList,NULL);
	m_pMySql = new MySql_DB(SERVER_IP,USER_NAME , PASSWORD);
	m_pMySql->ConnectToServer(DATA_BASE);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
 CServerAppForUser::~CServerAppForUser()
{
	delete(m_pMySql);
    pthread_mutex_destroy(&m_MutexForRecvList);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
CServerAppForDevice::CServerAppForDevice(StreamSocket v_socket)
{
  m_socket = v_socket;
  m_socket.setKeepAlive(true);

  Poco::Timespan timeout(3 ,0);
  m_socket.setReceiveTimeout(timeout);

  memset(m_pchCurtainState,'0',sizeof(m_pchCurtainState));
  m_nBit = 0;
  pthread_mutex_init(&m_MutexForCurtainState,NULL);
  pthread_mutex_init(&m_MutexForSendFlag,NULL);

}
 /********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
CServerAppForDevice::~CServerAppForDevice()
{
  pthread_mutex_destroy(&m_MutexForCurtainState);
  pthread_mutex_destroy(&m_MutexForSendFlag);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
string CServerAppForDevice::m_strGetCurtainState()
{
     pthread_mutex_lock(&m_MutexForCurtainState);
     string strReturn = m_pchCurtainState;
     pthread_mutex_unlock(&m_MutexForCurtainState);

     return strReturn;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForDevice::m_bSetCurtainState(int v_n,char v_chState)
{
     pthread_mutex_lock(&m_MutexForCurtainState);
     m_pchCurtainState[v_n] = v_chState;
     pthread_mutex_unlock(&m_MutexForCurtainState);

     return true;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForDevice::m_bSetSendFlag(bool v_bSendFlag)
{
     pthread_mutex_lock(&m_MutexForSendFlag);
     m_bSendFlag = v_bSendFlag;
     pthread_mutex_unlock(&m_MutexForSendFlag);
     return true;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForDevice::m_bGetSendFlag()
{
     pthread_mutex_lock(&m_MutexForSendFlag);
     bool bReturn = m_bSendFlag;
     pthread_mutex_unlock(&m_MutexForSendFlag);
     return bReturn;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForDevice::m_bkeepAlive()
{
  m_nBit++;
  if(m_nBit == 10)
  {
    m_nBit = 0;
    if(!m_bFormatSend("hello"))
    {
      m_setConnectState(false);
      LOG(ERROR) << "Send Error";
      return false;
    }

     string str;
     if(!m_bFormatRecv(str))
     {
       m_setConnectState(false);
       LOG(ERROR) << "Recive Error";
       return false;
     }
     if(str != "ack")
     {
       m_setConnectState(false);
       LOG(ERROR) << "Recive is not correct";
       return false;
     }

  }
  return true;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForDevice::m_bMovieCurtain()
{
   string strSend = "move";
   strSend += m_pchCurtainState;
   m_bFormatSend(strSend);
   return true;
}
 /********************************
 函  数：
 功  能：
 参  数：

 返回值：
 说  明：
 ********************************/
 bool bFormatSend(StreamSocket v_socket,string v_strSend)
 {                   //数据长度
   int  nDataSize = v_strSend.length() + 2;
   char *pSend = (char*)malloc(nDataSize);

   memset(pSend , 0 , nDataSize);
   strcpy(pSend, v_strSend.c_str());
   pSend[nDataSize-2] = 0x0d;
   pSend[nDataSize-1] = 0x0a;  //Attention : Must In Tail!

   if(v_socket.sendBytes(pSend ,nDataSize) == 0)
   {
	   LOG(ERROR) << "Send failed";
	   free(pSend);
	   return false;
   }
   free(pSend);
   return true;
 }
  /********************************
 函  数：
 功  能：
 参  数：

 返回值：
 说  明：
 ********************************/
 bool  bFormatRecv(StreamSocket v_socket,string &v_strRecv)
 {
	 char ch_Data[RECV_BUF_SIZE] = {0};                    //数据长度
	 if(v_socket.receiveBytes(ch_Data,RECV_BUF_SIZE) == 0)
	 {
		 LOG(ERROR) << "Recvive Failed";
		 return false;
	 }
     v_strRecv = ch_Data;
     v_strRecv = strEraseAll(v_strRecv,'\r');
     v_strRecv = strEraseAll(v_strRecv,'\n');
	 return true;
 }
 /********************************
 函  数：
 功  能：
 参  数：

 返回值：
 说  明：
 ********************************/
 bool  CServerApp::m_bFormatSend(string v_strSend)
 {                   //数据长度
   return bFormatSend(m_socket, v_strSend);
 }

 /********************************
 函  数：
 功  能：
 参  数：

 返回值：
 说  明：
 ********************************/
 bool  CServerApp::m_bFormatRecv(string &v_strRecv)
 {
	return bFormatRecv(m_socket,v_strRecv);
 }
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
void CServerAppForUser::m_ProcessRequest()
{
	 pthread_t Pid;
      if(pthread_create(&Pid,NULL,ThreadHandMessage,this))
      {
         LOG(ERROR) << "Create Listening Thread Failed";          //日志
         google::ShutdownGoogleLogging();          // 停止GLog
      }
}

void* ThreadHandMessage(void*p)
{
  CServerAppForUser *pApp = (CServerAppForUser*)p;
  pthread_mutex_lock(&pApp->m_MutexForDestory);
  pApp->m_recvMessage();
  pthread_mutex_unlock(&pApp->m_MutexForDestory);

  return 0;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool  CServerAppForUser::m_bPushRequestToList(string strRequest)
{
	pthread_mutex_lock(&m_MutexForRecvList); //检测新的消息
	m_recvList.push_back(strRequest);
    pthread_mutex_unlock(&m_MutexForRecvList);
    return true;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool  CServerAppForUser::m_bGetOutRequestFormList(string &strRequest)
{
    bool bReturn = false;
    pthread_mutex_lock(&m_MutexForRecvList); //检测新的消息
    int nSize = m_recvList.size();
    if(nSize > 0)
    {
     bReturn = true;
     strRequest = m_recvList[0];
     m_recvList.erase(m_recvList.begin());
    }
    else
        {
         strRequest = "";
        }
    pthread_mutex_unlock(&m_MutexForRecvList);

    return bReturn;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
void  CServerAppForUser::m_recvMessage()
{
	try
	{
		while(1)
		{
			if(!m_bGetConnectState())
			{
				LOG(ERROR) << "Connect is not exit";
				return ;
			}

            string strRequest;

            if(!m_bGetOutRequestFormList(strRequest))
            {
              usleep(30 * 1000);
  		      continue;
            }
            printf("%s\r\n",strRequest.c_str());
			if(!m_bSortRequest(strRequest))               //处理请求
			{
			  LOG(ERROR) << "request is not correct , disconnect this one";
			  m_setConnectState(false);
              m_socket.shutdown();
			  return ;
			}

			usleep(30 * 1000);
		}
	}
	catch( std::exception& e )
	{
		LOG(ERROR) << e.what();
		return ;
	}
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForUser::m_bSortRequest(string v_str_recv)         //所有的信息在这里分类
{
	LOG(INFO) << "analysis request";
	vector<string> MessagePackage = MySplit(v_str_recv , '|');
	int nSize = MessagePackage.size();
	if(nSize <= 0)
	{
		LOG(ERROR) << "request is not correct";
		return false;
	}
    string strOrder = MessagePackage[0];

    switch(m_nGetRequestType(strOrder))
    {
    case LOGIN          : return m_bProcessLogin(MessagePackage);
    case CONNECT_DEVICE : return m_bProcessConnectDevice(MessagePackage);
    case CURTAIN_STATE  : return m_bProcessCurtainState(MessagePackage);
    case CURTAIN_MOVE   : return m_bProcessCurtainMove(MessagePackage);
    default:return false;

    }
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
int CServerAppForUser::m_nGetRequestType(string v_str)
{
    if(v_str == Request[LOGIN])
	{
	 return LOGIN;
	}

	if(v_str == Request[CONNECT_DEVICE])
    {
       return CONNECT_DEVICE;
    }
	if(v_str == Request[CURTAIN_STATE])
    {
       return CURTAIN_STATE;
    }
    if(v_str == Request[CURTAIN_MOVE])
    {
      return CURTAIN_MOVE;
    }
	return -1;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForUser::m_bProcessLogin(vector<string> v_mesaagePackage)
{
	try
	{
		int nSize = v_mesaagePackage.size();
		if(nSize != 3)
		{
		    LOG(ERROR) << "parameter number error";
			return false;
		}
        m_nUserId = m_pMySql->JudgeLogin(v_mesaagePackage[1],v_mesaagePackage[2]);
		if(m_nUserId == 0)
		{
           m_bFormatSend(SendOrder[NO]);
		   LOG(INFO) << "User or password is not correct";
		   return true;
		}
		else
		{
           m_bFormatSend(SendOrder[YES]);
		   LOG(INFO) << "User and password is correct";
		   m_strUserName = v_mesaagePackage[1];
           m_bWriteLoginTime();
		   return true;
		}
	}
	catch( std::exception& e )
	{
		LOG(ERROR) << e.what();
		return false;
	}
}

/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForUser::m_bProcessConnectDevice(vector<string> v_mesaagePackage)
{
	try
	{
		int nSize = v_mesaagePackage.size();
		if(nSize != 2)
		{
		    LOG(ERROR) << "parameter number error";
			return false;
		}

      int nDeviceId = atoi(v_mesaagePackage[1].c_str());
      m_pDevice = g_DeviceManage.GetpAppDeviceById(nDeviceId);

      if(m_pDevice == NULL)
      {
        m_bFormatSend(SendOrder[NO]);
        LOG(ERROR) <<v_mesaagePackage[1] <<" Device is offline";
        return true;
      }
       m_bFormatSend(SendOrder[YES]);
       LOG(INFO) <<v_mesaagePackage[1] <<" Device is online";
      return true;

	}
	catch( std::exception& e )
	{
		LOG(ERROR) << e.what();
		return false;
	}
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForUser::m_bProcessCurtainState(vector<string> v_mesaagePackage)
{
 	try
	{
		int nSize = v_mesaagePackage.size();
		if(nSize != 1)
		{
		    LOG(ERROR) << "parameter number error";
			return false;
		}
        string strSend = "on";

        strSend += m_pDevice->m_strGetCurtainState();
        m_bFormatSend(strSend);
        LOG(INFO) << "Device State :" << strSend;

      return true;

	}
	catch( std::exception& e )
	{
		LOG(ERROR) << e.what();
		return false;
	}
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForUser::m_bProcessCurtainMove(vector<string> v_mesaagePackage)
{
  try
	{
		int nSize = v_mesaagePackage.size();
		if(nSize != 3)
		{
		    LOG(ERROR) << "parameter number error";
			return false;
		}
		int n = atoi(v_mesaagePackage[1].c_str()) - 1;

		if(n < 1 && n > 16)
        {
         LOG(ERROR) << "Curtain Number is Wrong";
         return false;
        }

		m_pDevice->m_bSetCurtainState(n,v_mesaagePackage[2][0]);
        m_pDevice->m_bSetSendFlag(true);
        string strSend = "yes";

        m_bFormatSend(strSend);
      return true;

	}
	catch( std::exception& e )
	{
		LOG(ERROR) << e.what();
		return false;
	}
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForUser::m_bWriteLoginTime()
{
   string strTime = strGetLocalTime();
   m_nLoginInfoId = m_pMySql->InsertLoginTimeAndGetId(m_nUserId,strTime);
   return true;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool CServerAppForUser::m_bWriteLogoutTime()
{
    if(m_nLoginInfoId == 0)
    {
      return false;
    }
    string strLogoutTime = strGetLocalTime();
    m_pMySql->SetLogoutTimeById(m_nLoginInfoId,strLogoutTime);
    return true;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
void  CServerApp::m_setConnectState(bool v_bState)
{
	pthread_mutex_lock(&m_MutexForState);
	m_bConnected = v_bState;
	pthread_mutex_unlock(&m_MutexForState);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool  CServerApp::m_bGetConnectState()
{
	pthread_mutex_lock(&m_MutexForState);
	bool bState = m_bConnected;
	pthread_mutex_unlock(&m_MutexForState);

	return bState;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
DeviceManager::DeviceManager()
{
	pthread_mutex_init(&m_MutexForDeviceList,NULL);
	m_pMySql = new MySql_DB(SERVER_IP,USER_NAME , PASSWORD);
	m_pMySql->ConnectToServer(DATA_BASE);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
DeviceManager::~DeviceManager()
{
    delete(m_pMySql);
	pthread_mutex_destroy(&m_MutexForDeviceList);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
void DeviceManager::AddDeviceNodeToList(CServerAppForDevice*v_DeviceNode)
{
    pthread_mutex_lock(&m_MutexForDeviceList);
	DeviceNodeList.push_back(v_DeviceNode);
    m_pMySql->SetDeviceStateById(v_DeviceNode->m_nDeviceId,"1");
	pthread_mutex_unlock(&m_MutexForDeviceList);
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
bool DeviceManager::DeletDeviceNodeByDeviceId(int v_nDeviceId)
{
    bool bReturn = false;
    pthread_mutex_lock(&m_MutexForDeviceList);
	vector<CServerAppForDevice*>::iterator it = DeviceNodeList.begin();
	for(; it != DeviceNodeList.end(); it++)
    {
      if(v_nDeviceId == (*it)->m_nDeviceId)
      {
        bReturn = true;
        m_pMySql->SetDeviceStateById(v_nDeviceId,"0");
        DeviceNodeList.erase(it);
        break;
      }
    }
	pthread_mutex_unlock(&m_MutexForDeviceList);

    return bReturn;
}
/********************************
函  数：
功  能：
参  数：

返回值：
说  明：
********************************/
CServerAppForDevice* DeviceManager::GetpAppDeviceById(int v_nDeviceId)
{
    CServerAppForDevice*pReturn = NULL;
    pthread_mutex_lock(&m_MutexForDeviceList);
	vector<CServerAppForDevice*>::iterator it = DeviceNodeList.begin();
	for(; it != DeviceNodeList.end(); it++)
    {
      if(v_nDeviceId == (*it)->m_nDeviceId)
      {
        pReturn = (*it);
        break;
      }
    }
	pthread_mutex_unlock(&m_MutexForDeviceList);

    return pReturn;
}
string strGetLocalTime()
{
    struct timeval tv;
    char buf[64];

    gettimeofday(&tv, NULL);
    strftime(buf, sizeof(buf)-1, "%Y-%m-%d %H:%M:%S", localtime(&tv.tv_sec));
    fprintf(stderr, "%s ", buf);
    string strReturn = buf;
    return strReturn;
}
